#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <thread>
#include<sys/types.h>
#include<sys/stat.h>

#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>

#include <gui/BufferQueue.h>
#include <gui/BufferQueueDefs.h>
#include <gui/ConsumerBase.h>
#include <ui/FenceTime.h>
#include <ui/GraphicBuffer.h>

#include "platform_gralloc4.h" //librga

#include "FakeCameraConsumer.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <fcntl.h>

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <fcntl.h>

#include "common.h"

using namespace android;

#include "common.h"

#include <RockchipRga.h>

#define RGA_VER (1.0)
#define RGA_ACTIVE_W (2048)
#define RGA_VIRTUAL_W (4096)
#define RGA_ACTIVE_H (2048)
#define RGA_VIRTUAL_H (2048)


int rga_nv12_scale_crop(
		int src_width, int src_height,
		unsigned long src_fd, unsigned long dst_fd,
		int dst_width, int dst_height,
		int zoom_val, bool mirror, bool isNeedCrop,
		bool isDstNV21, bool is16Align, bool isYuyvFormat)
{
    int ret = 0;
    rga_info_t src,dst;
    int zoom_cropW,zoom_cropH;
    int ratio = 0;
    int zoom_top_offset=0,zoom_left_offset=0;

    RockchipRga& rkRga(RockchipRga::get());

    memset(&src, 0, sizeof(rga_info_t));
    if (isYuyvFormat) {
        src.fd = -1;
        src.virAddr = (void*)src_fd;
    } else {
        src.fd = src_fd;
    }
    src.mmuFlag = ((2 & 0x3) << 4) | 1 | (1 << 8) | (1 << 10);
    memset(&dst, 0, sizeof(rga_info_t));
    dst.fd = dst_fd;
    dst.mmuFlag = ((2 & 0x3) << 4) | 1 | (1 << 8) | (1 << 10);

    if((dst_width > RGA_VIRTUAL_W) || (dst_height > RGA_VIRTUAL_H)){
        printf("(dst_width > RGA_VIRTUAL_W) || (dst_height > RGA_VIRTUAL_H), switch to arm \n");
        ret = -1;
        goto END;
    }

    //need crop ? when cts FOV,don't crop
    if(isNeedCrop && (src_width*100/src_height) != (dst_width*100/dst_height)) {
        ratio = ((src_width*100/dst_width) >= (src_height*100/dst_height))?
                (src_height*100/dst_height):
                (src_width*100/dst_width);
        zoom_cropW = (ratio*dst_width/100) & (~0x01);
        zoom_cropH = (ratio*dst_height/100) & (~0x01);
        zoom_left_offset=((src_width-zoom_cropW)>>1) & (~0x01);
        zoom_top_offset=((src_height-zoom_cropH)>>1) & (~0x01);
    }else{
        zoom_cropW = src_width;
        zoom_cropH = src_height;
        zoom_left_offset=0;
        zoom_top_offset=0;
    }

    if(zoom_val > 100){
        zoom_cropW = zoom_cropW*100/zoom_val & (~0x01);
        zoom_cropH = zoom_cropH*100/zoom_val & (~0x01);
        zoom_left_offset = ((src_width-zoom_cropW)>>1) & (~0x01);
        zoom_top_offset= ((src_height-zoom_cropH)>>1) & (~0x01);
    }

    //usb camera height align to 16,the extra eight rows need to be croped.
    if(!is16Align){
        zoom_top_offset = zoom_top_offset & (~0x07);
    }

    rga_set_rect(&src.rect, zoom_left_offset, zoom_top_offset,
                zoom_cropW, zoom_cropH, src_width,
                src_height, HAL_PIXEL_FORMAT_YCrCb_NV12);
    if (isDstNV21)
        rga_set_rect(&dst.rect, 0, 0, dst_width, dst_height,
                    dst_width, dst_height,
                    HAL_PIXEL_FORMAT_YCrCb_420_SP);
    else
        rga_set_rect(&dst.rect, 0,0,dst_width,dst_height,
                    dst_width,dst_height,
                    HAL_PIXEL_FORMAT_YCrCb_NV12);

    if (mirror)
        src.rotation = DRM_RGA_TRANSFORM_FLIP_H;
    //TODO:sina,cosa,scale_mode,render_mode
    ret = rkRga.RkRgaBlit(&src, &dst, NULL);
    if (ret) {
        printf("%s:rga blit failed\n", __FUNCTION__);
        goto END;
    }

    END:
    return ret;
}


//#define UNIXSTR_PATH "foo.socket"
#define UNIXSTR_PATH "/data/sock_trb"

//client init
//server init

int ipc_fd_socket_init()
{
	int fd;
	struct sockaddr_un servaddr;
	int ret;
	struct msghdr msg;
	struct iovec iov[1];
	char buf[100];
	union {  //保证cmsghdr和msg_control对齐
		struct cmsghdr cm;
		char control[CMSG_SPACE(sizeof(int))];
	} control_un;
	struct cmsghdr *pcmsg;
 
	fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (fd < 0)
    {
		printf ( "socket failed. err: %s\n", strerror(errno));
		return -1;
	}

	bzero (&servaddr, sizeof(servaddr));
	servaddr.sun_family = AF_UNIX;
	strcpy( servaddr.sun_path, UNIXSTR_PATH);
 
	ret = connect(fd, (struct sockaddr*)&servaddr, sizeof(servaddr));
	if (ret < 0)
    {
		printf ( "connect failed. err: %s\n", strerror(errno));
		return -1;
	}

	return fd;
}

int ipc_fd_socket_deinit(int sock)
{
    //shutdown(sock);
    close(sock);
}

//也可以同时发送多个fd,这里仅实现一次发送一个fd
int ipc_fd_socket_send(int sock, int fd, char *data_ptr, int data_len)
{
	int ret;
	struct msghdr msg;
	struct iovec iov[1];
	union {  //保证cmsghdr和msg_control对齐
		struct cmsghdr cm;
		char control[CMSG_SPACE(sizeof(int))];
	} control_un;
	struct cmsghdr *pcmsg;

	//udp需要,tcp无视
	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	iov[0].iov_base = data_ptr;
	iov[0].iov_len = data_len;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;
	//设置缓冲区和长度
	msg.msg_control = control_un.control;
	msg.msg_controllen = sizeof(control_un.control);
	//直接通过CMSG_FIRSTHDR取得附属数据
	pcmsg = CMSG_FIRSTHDR(&msg);
	pcmsg->cmsg_len = CMSG_LEN(sizeof(int));
	pcmsg->cmsg_level = SOL_SOCKET;
	pcmsg->cmsg_type = SCM_RIGHTS;  //指明发送的是描述符
	*((int*)CMSG_DATA(pcmsg)) = fd;  //把描述符写入辅助数据
 
	ret = sendmsg(sock, &msg, sizeof(msg));  //send filedescriptor
    if (ret == -1)
    {
	    printf ("ret = %d, send filedescriptor = %d, err:%s\n", ret, fd, strerror(errno));
    }

    return ret;
}

//如何知道接收到多少数据？char *data_ptr, int data_len
int ipc_fd_socket_recv(int sock, int *fd, char *data_ptr, int data_len)
{
	int ret;
	struct sockaddr_un servaddr, cliaddr;
	socklen_t clilen;
	struct msghdr msg;
	struct iovec iov[1];
	char buf [100]; 
	union {  //对齐
		struct cmsghdr cm;
		char control[CMSG_SPACE(sizeof(int))];
	}  control_un;
	struct cmsghdr *pcmsg;

    msg.msg_name  = NULL;
    msg.msg_namelen  = 0;
    //设置数据缓冲区
    iov[0].iov_base = data_ptr;
    iov[0].iov_len = data_len;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    //设置辅助数据缓冲区和长度
    msg.msg_control = control_un.control;
    msg.msg_controllen  =  sizeof(control_un.control) ;
    //接收

    printf("recv iov[0].iov_len=%d\n", iov[0].iov_len);

    ret = recvmsg(sock, &msg, 0);
    if ( ret <= 0 )
    {
        printf ("ret = %d, err:%s\n", ret, strerror(errno));
        return ret;
    }

    printf("recv22 iov[0].iov_len=%d, data=%s ret=%d\n", iov[0].iov_len, iov[0].iov_base, ret);
    //接收到的数据长度ret, 数据在iov[0].iov_base


    //检查是否收到了辅助数据，以及长度
    if((pcmsg = CMSG_FIRSTHDR(&msg) ) != NULL && ( pcmsg->cmsg_len == CMSG_LEN(sizeof(int))))
    {
        if ( pcmsg->cmsg_level  !=  SOL_SOCKET ) {
            printf("cmsg_leval is not SOL_SOCKET\n");
            return -1;
        }

        if ( pcmsg->cmsg_type != SCM_RIGHTS ) {
            printf ( "cmsg_type is not SCM_RIGHTS" );
            return -1;
        }

        //这就是我们接收的描述符
        //这就是我们接收的描述符
        *fd = *((int*)CMSG_DATA(pcmsg));
        printf ( "000055 recv fd = %d\n", *fd );
    }

    return ret;
}
